import Base from '@/common/cmdBase/cmdBase';
import { ToolBarEvents } from '@/components/CmdBar/CmdBottomBtn/type';
import { KEYBOARD_KEY, ManagerId, userEvents } from 'nextcae-base';
import { widgetManager } from '@/common/managers';
import { EntityInfo, EntityPartType } from '@amcax/web-render';
import PickManager from './PickManager';
import { EntOtpMod, OrtherKey, TabsType } from './type';
import { useFocusStore } from 'nextcae-base/src/common/store';
import { EventNum } from 'nextcae-base/src/types/event';
import { isArray } from 'lodash';
import { labelManager } from '@/common/preview';
export class PickSelect extends Base {
  private _isMultiPick = false;
  public pickIsCall = false;
  private _isRegister: boolean = false; // 是否注册事件;
  public pickMode: EntityPartType = EntityPartType.face; // 底部工具栏的pick type
  private hoveres: EntityInfo = null;
  // 用于存放所有selected的数据用于显隐和广播
  private selectedEntMaps: { [key: string]: Map<string, EntityInfo> } = {};
  constructor(private parent: PickManager) {
    super();
  }
  set isMultiPick(value: boolean) {
    this._isMultiPick = value;
  }
  get tabsType() {
    return this.parent.tabsType;
  }
  get selectedEnts() {
    return Array.from(this.selectedEntMap.values());
  }
  // 当前选中pick操作下选中的数据
  get selectedEntMap() {
    if (!this.selectedEntMaps?.[this.focusId]) {
      this.selectedEntMaps[this.focusId] = new Map();
    }
    return this.selectedEntMaps[this.focusId];
  }
  // 当前选中pick组件的id
  get focusId() {
    if (this.parent.isPick) {
      return OrtherKey.PICK;
    } else if (this.parent.isFocus) {
      return OrtherKey.FOCUS;
    } else {
      const allPickIds = useFocusStore.getState()?.allPickIds;
      const focusId = useFocusStore.getState()?.focusId;
      if (allPickIds.includes(focusId)) {
        return useFocusStore.getState()?.focusId;
      } else {
        return null;
      }
    }
  }
  // 获取不能被取消hover的ids eg: 当不是当前的hover的
  get banShiftPickEnts() {
    const banShiftEnts = [];
    for (const key in this.selectedEntMaps) {
      if (key !== this.focusId && !Object.values(OrtherKey).includes(key)) {
        banShiftEnts.push(...Array.from(this.selectedEntMaps[key].values()));
      }
    }
    return banShiftEnts;
  }
  getPickMode(): EntityPartType {
    return this.pickMode;
  }
  addPickInfos(ents: EntityInfo[] | EntityInfo) {
    if (Array.isArray(ents)) {
      ents.forEach((item) => this.addPickInfos(item));
    } else {
      this.selectedEntMap.set(this.parent.makeId(ents), ents);
    }
  }
  removePickInfos(ents: EntityInfo[] | EntityInfo) {
    if (Array.isArray(ents)) {
      ents.forEach((item) => this.removePickInfos(item));
    } else {
      this.selectedEntMap.delete(this.parent.makeId(ents));
    }
  }
  setPickMode(value?: EntityPartType) {
    const temp = value ?? this.pickMode;
    if (this.tabsType === TabsType.Element) {
      this.pickMode =
        temp === EntityPartType.face ? EntityPartType.element : temp;
    } else {
      this.pickMode =
        temp === EntityPartType.element ? EntityPartType.face : temp;
    }
    this.parent.isPick && this.parent.optionChange();
  }
  onMultipleSelected = (selectArr: EntityInfo[]): void => {
    selectArr.forEach((item) => {
      this.addPickInfos(item);
    });
    // 广播数据
    this.broadcastAllEnts();
    this.broadcastSelectedEnts(selectArr);
  };
  onBeforeHovered = (e: EntityInfo) => {
    if (!this.focusId) {
      return true;
    }
    let isShiftBanEnt = false;
    let hasOrtherSelected = false;
    // 选中的实体不能shift取消
    if (this.parent.isCmd) {
      hasOrtherSelected = this.banShiftPickEnts.some((it) =>
        this.parent.isEntEqual(it, e),
      );
      this.shift && (isShiftBanEnt = hasOrtherSelected);
    }
    return (
      this.parent.onBeforeHovered(e, this.shift) &&
      !isShiftBanEnt &&
      !hasOrtherSelected
    );
  };
  registerEvents() {
    if (!this._isRegister) {
      super.registerEvents();
      this._isRegister = true;
      this.parent.optionChange();
      this.clearSelected();
    }
    this.enablePick = true;
  }
  unregisterEvents() {
    if (this._isRegister) {
      super.unregisterEvents();
      this._isRegister = false;
      widgetManager.hint('');
      this.parent.setPickStatus(null);
    }
  }
  onMouseLeft = (e: EntityInfo, selected?: boolean) => {
    const resE = this.parent.onMouseLeft(e, this.shift ? false : selected);
    if (!selected) {
      this.removePickInfos(e);
      this.removePickInfos(resE);
    } else {
      if (!this.shift) {
        this.handleAddSelected(resE, this._isMultiPick);
      } else {
        this.removePickInfos(resE);
      }
    }
    // 广播数据
    this.broadcastAllEnts();
    this.broadcastSelectedEnts(resE);
  };
  // 广播所有选中的实体
  broadcastAllEnts() {
    if (!this.parent.isPick) {
      userEvents.emit(EventNum.All_SELECT_ENTS, {
        selectedEnts: this.selectedEnts,
        focusId: this.focusId,
      });
    }
  }
  // 广播选中的实体
  broadcastSelectedEnts(ents: EntityInfo[]) {
    if (!this.parent.isPick) {
      const res = { ents, status: this.parent.pickStatus };
      userEvents.emit(EventNum.PICK_SELECT_ENTS, res);
    }
  }
  handleAddSelected = (e: EntityInfo | EntityInfo[], isMultiPick = false) => {
    if (this.enableBoxSelect || this.parent.isPick || isMultiPick) {
      this.addPickInfos(e);
    } else {
      this.setEntsSelected(true, this.focusId, true, isArray(e) ? e : [e]);
    }
  };
  onHoveredNull = () => {
    this.unHover();
    labelManager().removeCss2DLabel();
  };
  unHover = () => {
    if (this.hoveres) {
      this.parent.handle(this.hoveres, false, EntOtpMod.HOVER);
    }
    this.hoveres = null;
  };
  onHovered = (e: EntityInfo) => {
    if (
      this.hoveres &&
      this.parent.makeId(e) !== this.parent.makeId(this.hoveres)
    ) {
      this.unHover();
    }
    this.parent.handle(e, true, EntOtpMod.HOVER, this.shift);
    this.hoveres = e;
    userEvents.emit(EventNum.PICK_HOVER_ENT, e);
    this.mainRenderer.render();
  };
  /**
   * @description 设置实体选中状态 局部更新
   * @param {boolean} selected 选中状态
   * @param {string} focusId 聚焦id
   * @param {boolean} isClear 是否清空
   * @param {EntityInfo[]} pickInfos formData数据 可不填
   * */
  setEntsSelected = (
    selected: boolean = false,
    focusId: string = null,
    isClear = false,
    pickInfos: EntityInfo[] = null,
  ) => {
    if (focusId == null && pickInfos == null) {
      for (const key in this.selectedEntMaps) {
        const ents = Array.from(this.selectedEntMaps[key].values());
        this.controlSelected(ents, selected);
        isClear && this.selectedEntMaps[key].clear();
      }
    } else {
      !this.selectedEntMaps?.[focusId] &&
        (this.selectedEntMaps[focusId] = new Map());
      const ents = Array.from(this.selectedEntMaps?.[focusId]?.values());
      if (focusId && (pickInfos == null || !pickInfos.length)) {
        this.controlSelected(ents, selected);
        isClear && this.selectedEntMaps[focusId].clear();
      } else if (focusId && pickInfos && selected) {
        const { oldItems, newItems } = this.compareArray(ents, pickInfos);
        this.controlSelected(oldItems, false);
        oldItems.forEach((item) =>
          this.selectedEntMaps[focusId].delete(this.parent.makeId(item)),
        );
        this.controlSelected(newItems, true);
        newItems.forEach((item) =>
          this.selectedEntMaps[focusId].set(this.parent.makeId(item), item),
        );
      }
    }
    isClear && this.parent.getEntSelect().release();
    this.mainRenderer.render();
  };
  /**
   * @description  比较两个数组找出共同的和老数据比新数据少了那些和多了那些数据
   * @param {EntityInfo[]} oldArray 老数据
   * @param {EntityInfo[]} newArray 新数据
   * @returns {commonItems: EntityInfo[], oldItems: EntityInfo[], newItems: EntityInfo[]} 共同的、老数据比新数据多了的数据、新数据比老数据多了的数据
   * */
  compareArray(oldArray: EntityInfo[], newArray: EntityInfo[]) {
    const commonItems = oldArray.filter((item) =>
      newArray.some((newItem) => this.parent.isEntEqual(item, newItem)),
    );
    const oldItems = oldArray.filter(
      (item) =>
        !commonItems.some((newItem) => this.parent.isEntEqual(item, newItem)),
    );
    const newItems = newArray?.filter(
      (item) =>
        !commonItems.some((newItem) => this.parent.isEntEqual(item, newItem)),
    );
    return { commonItems, oldItems, newItems };
  }

  // 控制选中状态
  private controlSelected(ents: EntityInfo[], selected: boolean) {
    ents.forEach((item) => {
      // const mid = this.getMid(item);
      // TODO 暂时都是 ManagerId.Mesh
      this.setSelectOrHover(item, selected, EntOtpMod.SELECTED, ManagerId.Mesh);
    });
  }
  getMid(e: EntityInfo) {
    let mId = ManagerId.Geometry;
    if (e?.type === EntityPartType.element) {
      mId = ManagerId.Mesh;
    }
    return mId;
  }
  release(): void {
    this.selectedEntMaps = {};
  }
  onKeyUp = (e: KeyboardEvent) => {
    if (e.key === KEYBOARD_KEY.ESC) {
      userEvents.emit(ToolBarEvents.ESC);
    }
  };
}
